package cn.fintecher.pangolin.service.common.service;

import cn.fintecher.pangolin.common.model.*;
import cn.fintecher.pangolin.common.utils.*;
import cn.fintecher.pangolin.entity.elastic.UploadFile;
import cn.fintecher.pangolin.service.common.elastic.UploadFileElastic;
import com.google.common.collect.Lists;
import org.apache.commons.io.FileUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URL;
import java.util.List;
import java.util.Objects;

/**
 * Created by ChenChang on 2017/12/26.
 */
@Service("uploadFileService")
public class UploadFileService {
    private final Logger log = LoggerFactory.getLogger(UploadFileService.class);
    @Autowired
    private UploadFileElastic uploadFileElastic;

    @Value("${file.dir}")
    private String fileDir;

    @Value("${file.base-url}")
    private String baseUrl;
    @Autowired
    private Snowflake snowflake;

    public UploadFile findOne(String id) {
        UploadFile uploadFile = uploadFileElastic.findById(id).get();
        uploadFile.setUrl(baseUrl + "/" + uploadFile.getFileName());
        return uploadFile;
    }

    public File findOneFileById(String id) {
        UploadFile uploadFile = findOne(id);
        return new File(fileDir + "/" + uploadFile.getFileName());
    }

    public UploadFile findOneFileByName(String fileName) {
        return uploadFileElastic.findByFileName(fileName);
    }

    public UploadFile fileUpload(MultipartFile file) throws Exception {
        return fileUpload(file.getInputStream(), file.getOriginalFilename(), fileDir, "");

    }

    public UploadFile fileUpload(InputStream inputStream, String originalName, String filePath, String repair) throws Exception {
        String extensionName = originalName.substring(originalName.lastIndexOf(".") + 1);
        String fileId = String.valueOf(snowflake.next());
        String fileName = fileId + "." + extensionName;
        saveToDisk(inputStream, extensionName, fileId, filePath);
        UploadFile uploadFile = saveUploadFile(fileId, repair.concat(fileName), originalName, extensionName);
        inputStream.close();
        return uploadFile;
    }

    public UploadFile uploadVisitFile(InputStream inputStream, String originalName, String filePath, String repair) throws Exception {
        String extensionName = originalName.substring(originalName.lastIndexOf(".") + 1);
        String fileId = String.valueOf(snowflake.next());
        String fileName = originalName;
        saveToDisk(inputStream, extensionName, originalName.substring(0, originalName.lastIndexOf(".")), filePath);
        UploadFile uploadFile = saveVisitFile(fileId, fileName, originalName, extensionName, baseUrl.concat(repair), fileDir.concat("/").concat(originalName));
        inputStream.close();
        return uploadFile;

    }

    private UploadFile saveVisitFile(String fileId, String fileName, String originalName, String extensionName, String filePath, String localPath) throws Exception {
        try {
            UploadFile uploadFile = new UploadFile();
            uploadFile.setOriginalName(originalName);
            uploadFile.setExtensionName(extensionName);
            uploadFile.setFileName(fileName);
            uploadFile.setId(fileId);
            uploadFile.setUrl(filePath + fileName);
            uploadFile.setLocalPath(localPath);
            return uploadFileElastic.save(uploadFile);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new Exception("file.saveRecord.error");
        }
    }

    /**
     * 文件写入硬盘
     *
     * @param inputStream
     * @param extensionName
     * @param fileId
     * @throws IOException
     */
    private void saveToDisk(InputStream inputStream, String extensionName, String fileId, String filePath) throws Exception {
        File outFile = null;
        OutputStream ot = null;
        try {
            outFile = new File(filePath);
            if (!outFile.exists()) {
                outFile.mkdirs();
            }
            String fileName = fileId + "." + extensionName;
            ot = new FileOutputStream(filePath + "/" + fileName);
            byte[] buffer = new byte[1024];
            int len;
            while ((-1 != (len = inputStream.read(buffer)))) {
                ot.write(buffer, 0, len);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new Exception("file.saveToDisk.error");
        } finally {
            if (Objects.nonNull(ot)) {
                ot.close();
            }
        }
    }

    /**
     * 保存文件记录到数据库
     *
     * @param fileId
     * @param fileName
     * @param originalName
     * @param extensionName
     * @return
     */
    private UploadFile saveUploadFile(String fileId, String fileName, String originalName, String extensionName) throws Exception {
        try {
            UploadFile uploadFile = new UploadFile();
            uploadFile.setOriginalName(originalName);
            uploadFile.setExtensionName(extensionName);
            uploadFile.setFileName(fileName);
            uploadFile.setId(fileId);
            uploadFile.setOperateTime(ZWDateUtil.getNowDateTime());
            uploadFile.setUrl(baseUrl + "/" + fileName);
            return uploadFileElastic.save(uploadFile);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new Exception("file.saveRecord.error");
        }
    }

    public VisitFile uploadCaseFileReduce(InputStream inputStream) throws Exception {
        String targetTempFilePath = FileUtils.getTempDirectoryPath().concat(File.separator).concat(File.separator).concat(ShortUUID.generateShortUuid()).concat(File.separator);
        List<String> directoryList;
        String dateStr = ZWDateUtil.getFormatNowDate("yyyyMMdd");

        try {
            directoryList = UnReduceFile.unZip(inputStream, targetTempFilePath, "UTF-8");
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            return null;
        }
        VisitFile visitFile = new VisitFile();
        if (Objects.nonNull(directoryList)) {
            for (String directoryName : directoryList) {
                File file = FileUtils.getFile(targetTempFilePath, directoryName);
                File[] array = file.listFiles();
                String[] paths = directoryName.split("/");
                String certificateNo = paths[paths.length - 1];
                String repair = "VISIT_FILE".concat("/").concat(certificateNo).concat("/").concat(dateStr);
                for (File f : array) {
                    try {
                        if (f.isDirectory()) {
                            continue;
                        }
                        InputStream in = new FileInputStream(f);
                        if (paths.length > 1) {
                            UploadFile uploadFile = uploadVisitFile(in, f.getName(), fileDir.concat("/").concat(repair), repair.concat("/"));
                            VisitFileModel visitFileModel = new VisitFileModel();
                            BeanUtils.copyProperties(uploadFile, visitFileModel);
                            visitFileModel.setCertificateNo(certificateNo);
                            visitFile.getVisitFileModels().add(visitFileModel);
                        } else {
                            UploadFile uploadFile = fileUpload(in, f.getName(), fileDir, "");
                            cn.fintecher.pangolin.common.model.UploadFile uploadFile1 = new cn.fintecher.pangolin.common.model.UploadFile();
                            BeanUtils.copyPropertiesIgnoreNull(uploadFile, uploadFile1);
                            visitFile.setExcelFile(uploadFile1);
                        }
                        in.close();
                    } catch (FileNotFoundException e) {
                        log.error(e.getMessage(), e);
                    } catch (IOException e) {
                        log.error(e.getMessage(), e);
                    }
                }
            }
            try {
                FileUtils.deleteDirectory(FileUtils.getFile(targetTempFilePath));
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        }
        return visitFile;
    }

    @Async
    public void downFileFromUrl(CuscdrFileModel fileModel) {
        try {
            //检查日期目录是否存在(/data/files/2019-07-18)
            String baseBath = fileDir.concat(File.separator).concat(fileModel.getDateStr());
            File filePath = new File(baseBath);
            if (!filePath.exists()) {
                filePath.mkdirs();
            }
            URL httpUrl = new URL(fileModel.getUrl());
            //文件存储到本地服务器
            File localFile = new File(baseBath.concat(File.separator).concat(fileModel.getFileName()));
            FileUtils.copyURLToFile(httpUrl, localFile, 10 * 1000, 60 * 1000);
        } catch (Exception e) {
            log.error("录音文件下载失败：{}", fileModel.getUrl());
            log.error(e.getMessage(), e);
        }
    }

    public TransVisitFile transVisitFiles(TransVisitFile transVisitFile) {
        List<FileInfo> fileInfos = transVisitFile.getFileInfos();
        String dateStr = ZWDateUtil.getFormatNowDate("yyyyMMdd");
        String repair = "VISIT_FILE".concat("/").concat(transVisitFile.getCert()).concat("/").concat(dateStr);
        String deskUrl = fileDir.concat("/").concat(repair);
        File file = new File(deskUrl);
        if (!file.exists()) {
            file.mkdirs();
        }
        fileInfos.forEach(fileInfo -> {
            UploadFile uploadFile = uploadFileElastic.findByFileName(fileInfo.getFileName());
            uploadFile.setUrl(baseUrl.concat(repair).concat("/").concat(fileInfo.getFileName()));
            uploadFile.setLocalPath(deskUrl.concat("/").concat(fileInfo.getFileName()));
            File oldFile = new File(fileDir.concat("/").concat(fileInfo.getFileName()));
            File newFile = new File(uploadFile.getLocalPath());
            oldFile.renameTo(newFile);
            fileInfo.setUrl(uploadFile.getUrl());
        });
        return transVisitFile;
    }

    public void deleteFiles(List<String> fileUrls) {
        fileUrls.forEach(url -> {
            File file = new File(url.replace(baseUrl, fileDir + "/"));
            file.delete();
        });
    }

    public List<UploadFile> findUploadByFileIds(String fileIds) {
        String fileIdArr[] = fileIds.split(",");
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.must(QueryBuilders.termsQuery("id.keyword", fileIdArr));
        return Lists.newArrayList(uploadFileElastic.search(boolQueryBuilder));
    }
}
